package com.jxw.scanpen.comm;

import static android.hardware.Camera.getCameraInfo;

import android.content.Context;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.SurfaceHolder;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

public class HYCamera {


    private static final String TAG = "HYCamera:";
    private static Camera mCamera;
    private int mBackCameraId = 0;
    // private int mCameraId;
    public static int mViewWidth = 128;//176
    public static int mViewHeight = 128;//144

    private static int mPreviewFormat = 0;
    private static OnCameraDataCallback mCallback;
    // buffering for one second
    private static final int NUM_PREVIEW_BUFFERS = 200;
    private static Object mLock = new Object();
    private static boolean bCameraReady = false;
    private static boolean isSetCallback = false;
 //   private Handler mHandler = new Handler();
    private static List<byte[]> prevCallbackBuffer = new ArrayList<>();
    private long startTime = 0L;

    static {
        for (int i = 0; i < NUM_PREVIEW_BUFFERS; i++) {
            prevCallbackBuffer.add(new byte[mViewWidth * mViewHeight * 4]);
        }
    }

    public HYCamera() {
        initCamera();
    }

    private void initCamera() {

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return ;
        }
        //  后置摄像头
        //     mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
        int countCamera = Camera.getNumberOfCameras();
        if (countCamera > 1) {
            mBackCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, cameraInfo);
        } else {
            mBackCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, cameraInfo);
        }
    }

    public boolean startCamera(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP|| Utils.isAppInstalled(context,Utils.TRANS_PKG)) {
            return false;
        }
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    synchronized (mLock) {
                        //  打开摄像头
                        Log.d("TAG", TAG + " openCamera"+mBackCameraId);
                        if (mCamera == null) {
                            mCamera = Camera.open(mBackCameraId);
                        }

                        try {
                            Log.d("TAG", TAG + "set parameters");
                            Camera.Parameters parameters = mCamera.getParameters();
                            List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
                            if (supportedPreviewSizes != null && supportedPreviewSizes.size() > 0) {
                                for (Camera.Size size : supportedPreviewSizes) {
                                    Log.i("TAG", TAG + " size width:" + size.width + ", " + size.height);
                                }
                            }
                            parameters.setPreviewSize(mViewWidth, mViewHeight);
                            Camera.Size size = parameters.getPreviewSize();
                            if(mViewWidth!=size.width || mViewHeight!=size.height){
                                if (mCallback != null) {
                                    mCallback.onChangeSize(size.width, size.height);
                                }
                            }
                            mViewHeight = size.height;
                            mViewWidth = size.width;
                            mPreviewFormat = parameters.getPreviewFormat();
                            mCamera.setParameters(parameters);
                            bCameraReady = true;

                            Log.d("TAG", TAG + "start preview end, w:" + mViewWidth + ", h:" + mViewHeight);
                        } catch (Exception e) {
                            Log.e("TAG", TAG + " setCameraParameters error:" + e.toString());
                        }

                        mLock.notifyAll();
                    }
                } catch (Exception e) {
                    Log.e("TAG", TAG + "startCamera error:" + e.toString());
                }
            }
        }.start();
        return mCamera != null;
    }

    private final String lightFilePath = "/sys/pen_irq/pen";
    private File lightFile = new File(lightFilePath);

    public void switchLight(String flag) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return;
        }
        try {
            FileOutputStream writerStream = new FileOutputStream(lightFile, true);
            BufferedWriter bufWriter = new BufferedWriter(
                    new OutputStreamWriter(writerStream, "UTF-8"));
            bufWriter.write(flag);
            bufWriter.flush();
            bufWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void startPreview(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP|| Utils.isAppInstalled(context,Utils.TRANS_PKG)) {
            return;
        }
        new Thread() {
            @Override
            public void run() {
                super.run();
                synchronized (mLock) {
                    switchLight("r1");
                    try {
                        Log.d("TAG", TAG + "startPreview camera: " + (mCamera != null) + " , isReady: " + bCameraReady + " , isSetCallback:" + isSetCallback);
                        if (mCamera == null || !bCameraReady) {
                            startCamera(context);
                            mLock.wait();
                        }

                        Log.d("TAG", TAG + "startPreview is Ok");
                        try {
                            Log.d("TAG", TAG + "set parameters flash");
                            Camera.Parameters parameters = mCamera.getParameters();
                            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                            mCamera.setParameters(parameters);
                        } catch (Exception e) {
                            Log.e("TAG", TAG + " set parameters flash error:" + e.toString());
                        }
                        for (int i = 0; i < NUM_PREVIEW_BUFFERS; i++) {
                            mCamera.addCallbackBuffer(prevCallbackBuffer.get(i));
                        }
                        mCamera.setPreviewCallback(myPreviewCallback);
                        if (isSetCallback) {
                            // 设置预览回调失败
                            Log.e("TAG", TAG + "setPreviewCallbackWithBuffer 失败！！！");
                            // 这里要重启摄像头
                        }

                        mCamera.startPreview();
                        isSetCallback = true;
                        startTime = System.currentTimeMillis();
                    } catch (Exception e) {
                        Log.e("TAG", TAG + "start camera preview error:" + e.toString());
                        stopCamera(context);
                        startCamera(context);
                    }
                }
            }
        }.start();
    }

    public void openLight() {


    }

    public void closeLight() {

    }


    private static Camera.PreviewCallback myPreviewCallback = new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            // Do not do too much work here, elsewise will drop camera preview fps seriously! The less code the better here!
            if (isSetCallback) {
                isSetCallback = false;
                Log.d("TAG", TAG + "onPreviewFrame is ok:  " + (mCallback != null));
            }
            if (mCamera != null) {
                mCamera.addCallbackBuffer(data);
            }
            if (mCallback != null) {
                mCallback.onPreviewFrame(data, mViewWidth, mViewHeight, mPreviewFormat);
            }
        }
    };

    public void stopPreview(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP|| Utils.isAppInstalled(context,Utils.TRANS_PKG)) {
            return ;
        }
        long time = System.currentTimeMillis() - startTime;
        synchronized (mLock) {
            switchLight("0");
            Log.d("TAG", TAG + "stopPreview:" + (mCamera != null) + ",  isSetCallback:" + isSetCallback + ", time:" + time);
            if (mCamera != null) {
                try {
                    Camera.Parameters parameters = mCamera.getParameters();
                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                    mCamera.setParameters(parameters);
                } catch (Exception e) {

                }
                try {
                    mCamera.stopPreview();
                } catch (Exception e) {
                    Log.e("TAG", TAG + "stopPreview error:" + e.toString());
                }
            }
        }
    }

    public void stopCamera(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || Utils.isAppInstalled(context,Utils.TRANS_PKG)) {
            return ;
        }
        synchronized (mLock) {
            Log.d("TAG", TAG + "stopCamera: " + (mCamera != null));
            bCameraReady = false;
            if (mCamera != null) {
                try {
                    Camera.Parameters parameters = mCamera.getParameters();
                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                    mCamera.setParameters(parameters);
                } catch (Exception e) {

                }
                try {
                    mCamera.setPreviewCallback(null);
                    mCamera.stopPreview();
                    mCamera.release();
                    mCamera = null;
                } catch (Exception e) {
                    Log.e("TAG", TAG + "stopCamera error:" + e.toString());
                }
            }
        }
    }

    public void destroyCamera(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return ;
        }
        mCallback = null;
        stopCamera(context);
        Log.d("TAG", TAG + "destroyCamera:" + (mCamera != null));
    }

    public void setCallback(OnCameraDataCallback callback) {
        this.mCallback = callback;
    }

    public interface OnCameraDataCallback {
        void onPreviewFrame(byte[] data, int width, int height, int format);
        void onChangeSize(int width, int height);
    }

}
